/*
 * Copyright (C) 2009 Rafael Fernandes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.phonebooksharing.services.servlets;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;

import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

import com.phonebooksharing.dto.GenericTransferDTO;
import com.phonebooksharing.dto.ReturnItem;
import com.phonebooksharing.dto.gallery.PostCardItem;
import com.phonebooksharing.dto.msg.VoiceMessageItem;
import com.phonebooksharing.services.ejb3.facade.MessageFacade;
import com.phonebooksharing.services.ejb3.utils.IConstants;
import com.phonebooksharing.services.utils.IOUtilities;

/**
 * Servlet implementation class DashboardServlet
 */
public class MessageServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
    private static Logger     log              = Logger.getLogger(MessageServlet.class);
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public MessageServlet() {
        super();
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	    PrintWriter pw = response.getWriter();
        response.setContentType("text/html");
        pw.print("<html><head/><body><h1>Welcome to Phonebook Sharing Services!</h1><br/><h3>You should be posting here!</h3></body></html>");
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        final String ac = request.getParameter("ac");
        if("a".equalsIgnoreCase(ac)) {//stream audio
            log.info("Request to stream [AUDIO] received... doing it so...");
            final String q = request.getParameter("q");
            
            ServletOutputStream sOutStream = response.getOutputStream();// this is for binary data
            streamBinaryData(messageFacade.getAudioPath(new Long(q)), "audio_mpeg", sOutStream, response);// for binary data
            
            return;
        }
        
        final ObjectOutputStream oos = new ObjectOutputStream(response.getOutputStream());
        final String type = request.getParameter("t");
        if("cm".equalsIgnoreCase(ac)) {//create message
            try {
                final ObjectInputStream ois = new ObjectInputStream(request.getInputStream());
                if("b".equalsIgnoreCase(type)) {//is batch
                    GenericTransferDTO gt = (GenericTransferDTO)ois.readObject();
                    
                    log.info("Creating [TEXT MESSAGE] in a [BATCH] manner = " + gt);
                    
                    oos.writeObject(new ReturnItem(true));
                } else {
                    log.info("Creating [TEXT MESSAGE] in a [INDIVIDUAL] manner = " + ois.readObject());
                    
                    oos.writeObject(new ReturnItem(true));
                }
            } catch (Exception e) {
                e.printStackTrace();
                oos.writeObject(new ReturnItem(false));
            }
        } else if("cv".equalsIgnoreCase(ac)) {//create voice
            try {
                if("c".equalsIgnoreCase(type)) {//create
                    final ObjectInputStream ois = new ObjectInputStream(request.getInputStream());
                    GenericTransferDTO gt = (GenericTransferDTO)ois.readObject();
                    oos.writeObject(messageFacade.create(gt.authItem, (VoiceMessageItem)gt.simpleItem));
                } else if("u".equalsIgnoreCase(type)) {//upload voice message
                    final String q = request.getParameter("q");
                    final String mt = request.getParameter("mt");
                    messageFacade.updateVoicePathTemp(new Long(q), uploadVoice(request, response, q, mt));
                } else if("d".equalsIgnoreCase(type)) {//distribute voice message
                    final String q = request.getParameter("q");
                    final ObjectInputStream ois = new ObjectInputStream(request.getInputStream());
                    GenericTransferDTO gt = (GenericTransferDTO)ois.readObject();
                    
                    if("i".equalsIgnoreCase(q)) { //individual
                        log.info("Creating [VOICE MESSAGE] for [INDIVIDUAL]");
                        
                        messageFacade.createResponse(gt.authItem, gt.simpleID, (VoiceMessageItem)gt.simpleItem);
                    } else if("g".equalsIgnoreCase(q)) { //group
                        log.info("Creating [VOICE MESSAGE] for [GROUP]");
                    } 
                    oos.writeObject(new ReturnItem(true));
                }
            } catch (Exception e) {
                e.printStackTrace();
//                oos.writeObject(new ReturnItem(false));
            }
        } else if("cpc".equalsIgnoreCase(ac)) {//create postcard
            try {
                if("c".equalsIgnoreCase(type)) {//create
                    final ObjectInputStream ois = new ObjectInputStream(request.getInputStream());
                    GenericTransferDTO gt = (GenericTransferDTO)ois.readObject();
                    oos.writeObject(messageFacade.create(gt.authItem, (PostCardItem)gt.simpleItem));
                } else if("uf".equalsIgnoreCase(type)) {//upload postcard front
                    final String q = request.getParameter("q");
                    final String mt = request.getParameter("mt");
                    messageFacade.updatePostcardFrontPathTemp(new Long(q), uploadFrontPostCard(request, response, q, mt));
                    
                } else if("ub".equalsIgnoreCase(type)) {//upload postcard back
                    final String q = request.getParameter("q");
                    final String mt = request.getParameter("mt");
                    messageFacade.updatePostcardBackPathTemp(new Long(q), uploadBackPostCard(request, response, q, mt));
                    
                } else if("d".equalsIgnoreCase(type)) {//distribute postcard
//                    final ObjectInputStream ois = new ObjectInputStream(request.getInputStream());
//                    GenericTransferDTO gt = (GenericTransferDTO)ois.readObject();
                    log.info("Distributing [POSTCARD] for [GROUP]");
                    
                    oos.writeObject(new ReturnItem(true));
                }
            } catch (Exception e) {
                e.printStackTrace();
                oos.writeObject(new ReturnItem(false));
            }
        }
	}
	
	private String uploadFrontPostCard(HttpServletRequest request, HttpServletResponse resp, String postcardID, String mimeType) {
        return upload(request, resp, IConstants.ROOT_FOR_POSTCARD + "f" + postcardID + getMimeTypeExtension(mimeType));
    }
	
    private String uploadBackPostCard(HttpServletRequest request, HttpServletResponse resp, String postcardID, String mimeType) {
        return upload(request, resp, IConstants.ROOT_FOR_POSTCARD + "b" + postcardID + getMimeTypeExtension(mimeType));
    }
    
	private String uploadVoice(HttpServletRequest request, HttpServletResponse resp, String voiceID, String mimeType) {
	    return upload(request, resp, IConstants.ROOT_FOR_VOICE + voiceID + getMimeTypeExtension(mimeType));
    }
	
	private String upload(HttpServletRequest request, HttpServletResponse resp, String fileName) {
        try {
            InputStream in = new DataInputStream(request.getInputStream());
            IOUtilities.ensureDirectory(fileName);
            
            final FileOutputStream fos = new FileOutputStream(fileName);
            OutputStream out = new BufferedOutputStream(fos, 4 * 1024);
            byte[] b = new byte[4 * 1024];
            int read;
            while ((read = in.read(b)) != -1) {
                out.write(b, 0, read);
            }
            out.flush();
            
            return fileName;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
	
   private String getMimeTypeExtension(String mimeType) {
        if("audio/3gpp".equalsIgnoreCase(mimeType)) return ".3gpp";
        if("image/jpeg".equalsIgnoreCase(mimeType)) return ".jpg";
        return null;
    }
    
	@EJB
	private MessageFacade messageFacade;
	
	/**
     * This Method Handles streaming Binary data
     * <p>
     * 
     * @param String
     *            urlstr ex: http;//localhost/test.pdf etc.
     * @param String
     *            format ex: pdf or audio_wav or msdocuments etc.
     * @param ServletOutputStream
     *            outstr
     * @param HttpServletResponse
     *            resp
     */
    private void streamBinaryData(String song, String format, ServletOutputStream outstr, HttpServletResponse resp) {
        String ErrorStr = null;
        try {
            // find the right mime type and set it as contenttype
            resp.setContentType(getMimeType(format));
            BufferedInputStream bis = null;
            BufferedOutputStream bos = null;
            InputStream in = null;
            try {
                // VERY IMPORTANT: without this crap, the streaming to android doesnt work
                resp.setContentLength((int) new File(song).length());

                // Use Buffered Stream for reading/writing.
                in = new FileInputStream(song);
                bis = new BufferedInputStream(in);
                bos = new BufferedOutputStream(outstr);
                byte[] buff = new byte[24];
                int bytesRead;
                // Simple read/write loop.
                while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
                    bos.write(buff, 0, bytesRead);
                }
            } catch (Exception e) {
                e.printStackTrace();
                ErrorStr = "Error Streaming the Data";
                outstr.print(ErrorStr);
            } finally {
                if (in != null) in.close();
                if (bis != null) bis.close();
                if (bos != null) bos.close();
                
                if (outstr != null) {
                    outstr.flush();
                    outstr.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
	  
   /**
     * This Method Returns the right mime type for a particular format <p>
     * 
     * @param String format ex: xml or html etc.
     * 
     * @return String mimetype
     */
    private String getMimeType(String format) {
        if (format.equalsIgnoreCase("pdf")) // check the out type
            return "application/pdf";
        else if (format.equalsIgnoreCase("audio_basic"))
            return "audio/basic";
        else if (format.equalsIgnoreCase("audio_wav"))
            return "audio/wav";
        else if (format.equalsIgnoreCase("audio_mpeg"))
            return "audio/mpeg";
        else if (format.equalsIgnoreCase("image_gif"))
            return "image/gif";
        else if (format.equalsIgnoreCase("image_jpeg"))
            return "image/jpeg";
        else if (format.equalsIgnoreCase("image_bmp"))
            return "image/bmp";
        else if (format.equalsIgnoreCase("image_x-png"))
            return "image/x-png";
        else if (format.equalsIgnoreCase("msdownload"))
            return "application/x-msdownload";
        else if (format.equalsIgnoreCase("video_avi"))
            return "video/avi";
        else if (format.equalsIgnoreCase("video_mpeg"))
            return "video/mpeg";
        else if (format.equalsIgnoreCase("html"))
            return "text/html";
        else if (format.equalsIgnoreCase("xml"))
            return "text/xml";
        else
            return format;
    }
}
